package cm

import (
	"context"
	"fmt"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo/options"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"strings"
	"time"
	"twwch/k8s-admin/apis"
	"twwch/k8s-admin/application/base"
	cmRepo "twwch/k8s-admin/component/repo/cm"
	"twwch/k8s-admin/models/cm"
	"twwch/k8s-admin/models/common"
)

type ConfigMapService struct {
	base.BaseService
}

var svc = &ConfigMapService{}

func GetService() *ConfigMapService {
	svc.Logger = log.WithField("service", "cm")
	return svc
}
func (svc *ConfigMapService) getConfName(name string) string {
	if strings.HasSuffix(name, "-conf") {
		return name
	}
	return fmt.Sprintf("%v-conf", name)
}

func (svc *ConfigMapService) Get(ctx context.Context, req *cm.GetReq) (*cm.GetResp, error) {
	name := svc.getConfName(req.Name)
	if count, err := cmRepo.GetRepoInstance().GetBase().Count(ctx, bson.M{
		"conf_name": name,
		"namespace": req.Namespace,
	}); count == 0 || err != nil {
		if count == 0 {
			return nil, errors.New(name + "不存在")
		}
		svc.Logger.Error(ctx, err)
		return nil, err
	}
	cmf, err := apis.CoreV1().ConfigMaps(req.Namespace).Get(ctx, name, metav1.GetOptions{})
	if err != nil {
		svc.Logger.Error(ctx, err)
	}
	return &cm.GetResp{
		Cm: cmf,
	}, err
}

func (svc *ConfigMapService) Create(ctx context.Context, req *cm.CreateReq) (*cm.CreateResp, error) {
	name := svc.getConfName(req.Name)
	resp := &cm.CreateResp{
		Name: name,
		IsOk: false,
	}
	if count, err := cmRepo.GetRepoInstance().GetBase().Count(ctx, bson.M{
		"conf_name": name,
		"namespace": req.Namespace,
	}); count > 0 || err != nil {
		if count > 0 {
			return nil, errors.New(name + "已存在")
		}
		svc.Logger.Error(ctx, err)
		return resp, err
	}
	cmf, err := apis.CoreV1().ConfigMaps(req.Namespace).Create(ctx, &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      name,
			Namespace: req.Namespace,
		},
		Data: req.Data,
	}, metav1.CreateOptions{})
	if err != nil {
		svc.Logger.Error(ctx, err)
		return resp, err
	}
	_, err = cmRepo.GetRepoInstance().GetBase().UpdateOne(ctx,
		bson.M{
			"conf_name": name,
			"namespace": req.Namespace,
		},
		bson.M{
			"$set": bson.M{
				"cm": cmf,
			},
			"$setOnInsert": bson.M{
				"create_time": time.Now(),
			},
		}, options.Update().SetUpsert(true))
	if err != nil {
		svc.Logger.Error(ctx, err)
	}
	return &cm.CreateResp{
		Cm:   cmf,
		Name: name,
		IsOk: true,
	}, nil
}

func (svc *ConfigMapService) Update(ctx context.Context, req *cm.UpdateReq) (*cm.UpdateResp, error) {
	name := svc.getConfName(req.Name)
	if count, err := cmRepo.GetRepoInstance().GetBase().Count(ctx, bson.M{
		"conf_name": name,
		"namespace": req.Namespace,
	}); count == 0 || err != nil {
		if count == 0 {
			return nil, errors.New(name + "不存在")
		}
		svc.Logger.Error(ctx, err)
		return nil, err
	}
	cmf, err := apis.CoreV1().ConfigMaps(req.Namespace).Update(ctx, &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      name,
			Namespace: req.Namespace,
		},
		Data: req.Data,
	}, metav1.UpdateOptions{})
	if err != nil {
		svc.Logger.Error(ctx, err)
		return nil, err
	}
	_, err = cmRepo.GetRepoInstance().GetBase().UpdateOne(ctx,
		bson.M{
			"conf_name": name,
			"namespace": req.Namespace,
		},
		bson.M{
			"$set": bson.M{
				"cm":          cmf,
				"update_time": time.Now(),
			},
		})
	if err != nil {
		svc.Logger.Error(ctx, err)
	}
	return &cm.UpdateResp{
		Cm: cmf,
	}, nil
}

func (svc *ConfigMapService) Delete(ctx context.Context, req *cm.DeleteReq) (*common.Empty, error) {
	name := svc.getConfName(req.Name)
	if count, err := cmRepo.GetRepoInstance().GetBase().Count(ctx, bson.M{
		"conf_name": name,
		"namespace": req.Namespace,
	}); count == 0 || err != nil {
		if count == 0 {
			return nil, errors.New(name + "不存在")
		}
		svc.Logger.Error(ctx, err)
		return nil, err
	}
	err := apis.CoreV1().ConfigMaps(req.Namespace).Delete(ctx, name, metav1.DeleteOptions{})
	if err != nil {
		svc.Logger.Error(ctx, err)
		return nil, err
	}
	_, err = cmRepo.GetRepoInstance().GetBase().DeleteOne(ctx, bson.M{"conf_name": name, "namespace": req.Namespace})
	if err != nil {
		svc.Logger.Error(ctx, err)
	}
	return nil, nil
}

func (svc *ConfigMapService) List(ctx context.Context, req *cm.ListReq) (*cm.ListResp, error) {
	filters := bson.M{}
	if req.Namespace != "" {
		filters["namespace"] = req.Namespace
	}
	if req.Name != "" {
		filters["conf_name"] = bson.M{"$regex": req.Name, "$options": "$i"}
	}
	ops := options.Find().SetSort(bson.M{"namespace": 1})
	cms := make([]*cm.ConfigMap, 0)
	err := cmRepo.GetRepoInstance().GetBase().Find(ctx, filters, &cms, ops)
	if err != nil {
		svc.Logger.Error(ctx, err)
		return nil, err
	}
	count, err := cmRepo.GetRepoInstance().GetBase().Count(ctx, filters)
	if err != nil {
		svc.Logger.Error(ctx, err)
		return nil, err
	}
	return &cm.ListResp{
		Total: count,
		Items: cms,
	}, nil
}
